#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
小红书数据获取 Web 应用 - 后端服务
支持单个链接获取和批量Excel处理
"""

from flask import Flask, request, jsonify, send_file, render_template_string
from flask_cors import CORS
import pandas as pd
import os
import uuid
import tempfile
from datetime import datetime
import json
from xiaohongshu_api import get_xiaohongshu_note_info
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

app = Flask(__name__)
CORS(app)  # 允许跨域请求

# 配置参数
UPLOAD_FOLDER = 'uploads'
RESULT_FOLDER = 'results'
ALLOWED_EXTENSIONS = {'xlsx', 'xls'}

# 确保文件夹存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(RESULT_FOLDER, exist_ok=True)

# 进度存储 - 在实际应用中应该使用Redis或数据库
progress_store = {}

def allowed_file(filename):
    """检查文件类型是否允许"""
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/')
def index():
    """主页"""
    return render_template_string(HTML_TEMPLATE)

@app.route('/api/health', methods=['GET'])
def health_check():
    """健康检查接口"""
    logger.info("健康检查请求")
    return jsonify({
        'status': 'ok',
        'message': '小红书数据获取服务运行正常',
        'timestamp': datetime.now().isoformat(),
        'version': '1.0.0'
    })

@app.route('/api/single', methods=['POST'])
def get_single_note():
    """获取单个小红书笔记信息"""
    try:
        data = request.get_json()
        
        if not data or 'url' not in data:
            logger.warning("单个笔记获取: 缺少URL参数")
            return jsonify({
                'success': False,
                'error': '缺少URL参数'
            }), 400
        
        url = data['url'].strip()
        custom_cookie = data.get('cookie', '').strip()
        
        logger.info(f"开始处理单个笔记: {url}")
        
        if not url:
            logger.warning('链接不能为空')
            return jsonify({
                'success': False,
                'error': '链接不能为空'
            }), 400
        
        # 验证链接格式
        if 'xiaohongshu.com' not in url and 'xhs.cn' not in url:
            logger.warning(f"无效的小红书链接: {url}")
            return jsonify({
                'success': False,
                'error': '请提供有效的小红书链接'
            }), 400
        
        # 验证Cookie是否提供
        if not custom_cookie:
            logger.warning("用户未提供Cookie")
            return jsonify({
                'success': False,
                'error': '请提供Cookie。为了确保数据获取成功，必须从浏览器开发者工具中复制Cookie值。'
            }), 400
        
        # 使用用户提供的Cookie
        cookie_to_use = custom_cookie
        logger.info("使用用户提供的Cookie")
        
        # 获取笔记信息
        result = get_xiaohongshu_note_info(url, cookie_to_use)
        
        # 处理标签列表转换为字符串
        if isinstance(result.get('笔记标签'), list):
            result['笔记标签'] = ', '.join(result['笔记标签'])
        
        if result.get('错误信息'):
            logger.warning(f"获取笔记信息失败: {result['错误信息']}")
        else:
            logger.info(f"成功获取笔记信息: {result.get('笔记标题', '未知标题')}")
        
        return jsonify({
            'success': not bool(result.get('错误信息')),
            'data': result,
            'cookie_used': 'user_provided'  # 现在总是用户提供的
        })
        
    except Exception as e:
        logger.error(f"处理单个笔记时发生异常: {str(e)}")
        return jsonify({
            'success': False,
            'error': f'服务器内部错误: {str(e)}'
        }), 500

@app.route('/api/batch/upload', methods=['POST'])
def upload_batch_file():
    """上传批量处理文件"""
    try:
        if 'file' not in request.files:
            logger.warning("批量上传: 没有文件部分")
            return jsonify({
                'success': False,
                'error': '没有文件部分'
            }), 400
        
        file = request.files['file']
        
        if file.filename == '':
            logger.warning("批量上传: 没有选择文件")
            return jsonify({
                'success': False,
                'error': '没有选择文件'
            }), 400
        
        if not allowed_file(file.filename):
            logger.warning(f"批量上传: 不支持的文件类型: {file.filename}")
            return jsonify({
                'success': False,
                'error': '不支持的文件类型，请上传Excel文件(.xlsx或.xls)'
            }), 400
        
        # 生成唯一文件ID
        file_id = str(uuid.uuid4())
        filename = f"{file_id}.xlsx"
        filepath = os.path.join(UPLOAD_FOLDER, filename)
        
        # 保存文件
        file.save(filepath)
        logger.info(f"文件上传成功: {file.filename} -> {filename}")
        
        # 读取文件验证
        try:
            df = pd.read_excel(filepath)
            if df.empty:
                os.remove(filepath)
                logger.warning("上传的Excel文件为空")
                return jsonify({
                    'success': False,
                    'error': 'Excel文件为空'
                }), 400
            
            # 统计有效链接数量
            first_column = df.iloc[:, 0].astype(str)
            valid_urls = []
            
            for i, url in enumerate(first_column):
                if pd.isna(url) or url.strip() == '' or url == 'nan':
                    continue
                
                if 'xiaohongshu.com' in url or 'xhs.cn' in url:
                    valid_urls.append(url)
            
            logger.info(f"文件验证成功: 总行数{len(df)}, 有效链接{len(valid_urls)}个")
            
            return jsonify({
                'success': True,
                'file_id': file_id,
                'total_rows': len(df),
                'valid_urls': len(valid_urls)
            })
            
        except Exception as e:
            # 删除无效文件
            if os.path.exists(filepath):
                os.remove(filepath)
            logger.error(f"文件验证失败: {str(e)}")
            return jsonify({
                'success': False,
                'error': f'读取Excel文件失败: {str(e)}'
            }), 400
            
    except Exception as e:
        logger.error(f"文件上传异常: {str(e)}")
        return jsonify({
            'success': False,
            'error': f'文件上传失败: {str(e)}'
        }), 500

@app.route('/api/batch/process', methods=['POST'])
def process_batch_file():
    """处理批量文件"""
    try:
        data = request.get_json()
        
        if not data or 'file_id' not in data:
            return jsonify({
                'success': False,
                'error': '缺少文件ID'
            }), 400
        
        file_id = data['file_id']
        custom_cookie = data.get('cookie', '').strip()
        
        logger.info(f"开始批量处理: 文件ID={file_id}")
        
        # 验证Cookie是否提供
        if not custom_cookie:
            logger.warning("批量处理: 用户未提供Cookie")
            return jsonify({
                'success': False,
                'error': '请提供Cookie。批量处理需要Cookie以确保数据获取成功，请从浏览器开发者工具中复制Cookie值。'
            }), 400
        
        # 使用用户提供的Cookie
        cookie_to_use = custom_cookie
        logger.info("批量处理: 使用用户提供的Cookie")
        
        # 读取上传的文件
        filepath = os.path.join(UPLOAD_FOLDER, f"{file_id}.xlsx")
        
        if not os.path.exists(filepath):
            logger.error(f"文件不存在: {filepath}")
            return jsonify({
                'success': False,
                'error': '文件不存在，请重新上传'
            }), 400
        
        df = pd.read_excel(filepath)
        first_column = df.iloc[:, 0].astype(str)
        urls = first_column.tolist()
        
        # 初始化进度
        progress_store[file_id] = {
            'total': 0,
            'processed': 0,
            'success': 0,
            'error': 0,
            'current_url': '',
            'status': 'processing',
            'start_time': datetime.now()
        }
        
        # 统计有效URL总数
        valid_urls = []
        for i, url in enumerate(urls):
            if pd.isna(url) or url.strip() == '' or url == 'nan':
                continue
            
            if 'xiaohongshu.com' not in url and 'xhs.cn' not in url:
                continue
            
            valid_urls.append((i, url.strip()))
        
        progress_store[file_id]['total'] = len(valid_urls)
        logger.info(f"找到{len(valid_urls)}个有效链接")
        
        # 处理每个链接
        results = []
        
        for idx, (original_row, url) in enumerate(valid_urls):
            current_progress = progress_store[file_id]
            current_progress['processed'] = idx + 1
            current_progress['current_url'] = url
            
            logger.info(f"处理进度 {idx + 1}/{len(valid_urls)}: {url}")
            
            try:
                # 获取笔记信息
                result = get_xiaohongshu_note_info(url, cookie_to_use)
                
                # 处理标签列表
                if isinstance(result.get('笔记标签'), list):
                    result['笔记标签'] = ', '.join(result['笔记标签'])
                
                # 添加行号信息
                result['原始行号'] = original_row + 1
                results.append(result)
                
                if not result.get('错误信息'):
                    current_progress['success'] += 1
                    logger.info(f"成功获取: {result.get('笔记标题', '未知标题')}")
                else:
                    current_progress['error'] += 1
                    logger.warning(f"获取失败: {result.get('错误信息')}")
                
            except Exception as e:
                # 添加错误记录
                error_result = {
                    '原始行号': original_row + 1,
                    '笔记链接': url,
                    '笔记id': '',
                    '用户名': '',
                    '笔记标题': '',
                    '笔记正文': '',
                    '笔记标签': '',
                    '发布时间': '',
                    '点赞数': '',
                    '收藏数': '',
                    '评论数': '',
                    '分享数': '',
                    '形式': '',
                    '数据获取时间': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                    '错误信息': f'处理异常: {str(e)}'
                }
                results.append(error_result)
                current_progress['error'] += 1
                logger.error(f"处理异常: {url} - {str(e)}")
        
        # 更新进度状态
        progress_store[file_id]['status'] = 'completed'
        progress_store[file_id]['current_url'] = ''
        
        if not results:
            logger.warning("没有找到有效的小红书链接")
            return jsonify({
                'success': False,
                'error': '没有找到有效的小红书链接进行处理'
            }), 400
        
        # 创建结果Excel文件
        result_df = pd.DataFrame(results)
        
        # 重新排列列的顺序
        columns_order = [
            '原始行号', '笔记链接', '笔记id', '用户名', '笔记标题', 
            '笔记正文', '笔记标签', '发布时间', '点赞数', '收藏数', 
            '评论数', '分享数', '形式', '数据获取时间', '错误信息'
        ]
        
        result_df = result_df.reindex(columns=columns_order)
        
        # 保存结果文件
        result_filename = f"xiaohongshu_result_{file_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
        result_filepath = os.path.join(RESULT_FOLDER, result_filename)
        
        # 使用ExcelWriter来设置格式
        with pd.ExcelWriter(result_filepath, engine='openpyxl') as writer:
            result_df.to_excel(writer, index=False, sheet_name='小红书数据')
            
            # 获取工作表
            worksheet = writer.sheets['小红书数据']
            
            # 设置列宽
            column_widths = {
                'A': 10,  # 原始行号
                'B': 60,  # 笔记链接
                'C': 25,  # 笔记id
                'D': 15,  # 用户名
                'E': 40,  # 笔记标题
                'F': 60,  # 笔记正文
                'G': 30,  # 笔记标签
                'H': 20,  # 发布时间
                'I': 10,  # 点赞数
                'J': 10,  # 收藏数
                'K': 10,  # 评论数
                'L': 10,  # 分享数
                'M': 10,  # 形式
                'N': 20,  # 数据获取时间
                'O': 40,  # 错误信息
            }
            
            for col, width in column_widths.items():
                worksheet.column_dimensions[col].width = width
        
        # 清理上传的文件
        try:
            os.remove(filepath)
        except:
            pass
        
        # 处理完成后清理进度信息（延迟清理，给前端时间获取最终状态）
        # 实际应用中应该设置定时清理
        
        total_processed = len(valid_urls)
        success_count = progress_store[file_id]['success']
        error_count = progress_store[file_id]['error']
        
        logger.info(f"批量处理完成: 总计{total_processed}, 成功{success_count}, 失败{error_count}")
        
        return jsonify({
            'success': True,
            'result_file': result_filename,
            'statistics': {
                'total_processed': total_processed,
                'success_count': success_count,
                'error_count': error_count,
                'success_rate': f"{(success_count / total_processed * 100):.1f}%" if total_processed > 0 else "0%"
            },
            'cookie_used': 'user_provided'  # 现在总是用户提供的
        })
        
    except Exception as e:
        logger.error(f"批量处理异常: {str(e)}")
        return jsonify({
            'success': False,
            'error': f'处理文件时发生错误: {str(e)}'
        }), 500

@app.route('/api/batch/progress/<file_id>', methods=['GET'])
def get_progress(file_id):
    """获取批量处理进度"""
    try:
        if file_id not in progress_store:
            return jsonify({
                'success': False,
                'error': '找不到对应的处理任务'
            }), 404
        
        progress = progress_store[file_id]
        
        return jsonify({
            'success': True,
            'progress': {
                'total': progress['total'],
                'processed': progress['processed'],
                'success': progress['success'],
                'error': progress['error'],
                'current_url': progress['current_url'],
                'status': progress['status'],
                'percentage': round((progress['processed'] / progress['total'] * 100), 1) if progress['total'] > 0 else 0
            }
        })
        
    except Exception as e:
        logger.error(f"获取进度异常: {str(e)}")
        return jsonify({
            'success': False,
            'error': f'获取进度失败: {str(e)}'
        }), 500

@app.route('/api/download/<filename>', methods=['GET'])
def download_result(filename):
    """下载结果文件"""
    try:
        filepath = os.path.join(RESULT_FOLDER, filename)
        
        if not os.path.exists(filepath):
            return jsonify({
                'success': False,
                'error': '文件不存在'
            }), 404

        return send_file(
            filepath,
            as_attachment=True,
            download_name=filename,
            mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        )
        
    except Exception as e:
        return jsonify({
            'success': False,
            'error': f'下载文件时发生错误: {str(e)}'
        }), 500

@app.route('/api/template', methods=['GET'])
def download_template():
    """下载Excel模板文件"""
    try:
        # 创建模板文件
        template_data = {
            '小红书链接': [
                'https://www.xiaohongshu.com/explore/678f1e8200000000180053e1?xsec_token=WB-GbB2Qkxfu8WV7sq-4ZwOYQzlzEBBbutUZsQ96ZdVTk=&xsec_source=pc_wind_export',
                'https://www.xiaohongshu.com/explore/683974b4000000000f03291e?xsec_token=YBdXFMi-dt_u1jKfiE5iWjexdkVcCQ0kWSmmWKaFqRHT8%3D&xsec_source=pc_creatormng',
                '在此输入更多小红书链接...'
            ]
        }
        
        template_df = pd.DataFrame(template_data)
        
        # 创建临时文件
        with tempfile.NamedTemporaryFile(delete=False, suffix='.xlsx') as tmp_file:
            with pd.ExcelWriter(tmp_file.name, engine='openpyxl') as writer:
                template_df.to_excel(writer, index=False, sheet_name='小红书链接')
                
                # 设置列宽
                worksheet = writer.sheets['小红书链接']
                worksheet.column_dimensions['A'].width = 80
            
            return send_file(
                tmp_file.name,
                as_attachment=True,
                download_name='小红书批量获取模板.xlsx',
                mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            )
            
    except Exception as e:
        return jsonify({
            'success': False,
            'error': f'生成模板文件时发生错误: {str(e)}'
        }), 500

# HTML模板
HTML_TEMPLATE = r"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小红书数据获取工具</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css" rel="stylesheet">
    <style>
        body {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        .main-container {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 20px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
            margin: 2rem auto;
            max-width: 1200px;
            padding: 2rem;
        }
        .nav-tabs .nav-link {
            border: none;
            color: #666;
            font-weight: 500;
            padding: 1rem 2rem;
            border-radius: 10px 10px 0 0;
        }
        .nav-tabs .nav-link.active {
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            border: none;
        }
        .btn-primary {
            background: linear-gradient(135deg, #667eea, #764ba2);
            border: none;
            border-radius: 10px;
            padding: 0.75rem 2rem;
            font-weight: 500;
        }
        .btn-outline-primary {
            border: 2px solid #667eea;
            color: #667eea;
            border-radius: 10px;
            padding: 0.75rem 2rem;
            font-weight: 500;
        }
        .form-control, .form-select {
            border-radius: 10px;
            border: 2px solid #e9ecef;
            padding: 0.75rem 1rem;
        }
        .form-control:focus, .form-select:focus {
            border-color: #667eea;
            box-shadow: 0 0 0 0.25rem rgba(102, 126, 234, 0.25);
        }
        .card {
            border: none;
            border-radius: 15px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }
        .card-header {
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            border-radius: 15px 15px 0 0 !important;
            font-weight: 500;
        }
        .drop-zone {
            border: 3px dashed #667eea;
            border-radius: 15px;
            padding: 3rem;
            text-align: center;
            cursor: pointer;
            transition: all 0.3s ease;
            background: rgba(102, 126, 234, 0.05);
        }
        .drop-zone:hover, .drop-zone.drag-over {
            border-color: #764ba2;
            background: rgba(102, 126, 234, 0.1);
        }
        .progress {
            height: 1.5rem;
            border-radius: 10px;
            background: rgba(102, 126, 234, 0.1);
        }
        .progress-bar {
            background: linear-gradient(135deg, #667eea, #764ba2);
            border-radius: 10px;
        }
        .result-table {
            background: white;
            border-radius: 15px;
            overflow: hidden;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }
        .result-table th {
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            border: none;
            padding: 1rem;
            font-weight: 500;
        }
        .result-table td {
            padding: 1rem;
            border-bottom: 1px solid #e9ecef;
            vertical-align: middle;
        }
        .spinner-border-sm {
            width: 1rem;
            height: 1rem;
        }
        .alert {
            border-radius: 10px;
            border: none;
        }
        .alert-success {
            background: rgba(40, 167, 69, 0.1);
            color: #155724;
        }
        .alert-danger {
            background: rgba(220, 53, 69, 0.1);
            color: #721c24;
        }
        .alert-info {
            background: rgba(102, 126, 234, 0.1);
            color: #0c5460;
        }
        .header-title {
            background: linear-gradient(135deg, #667eea, #764ba2);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            font-weight: bold;
            text-align: center;
            margin-bottom: 2rem;
        }
        .processing-info {
            background: rgba(102, 126, 234, 0.05);
            border-radius: 10px;
            padding: 1rem;
            margin: 1rem 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="main-container">
            <h1 class="header-title display-4">
                <i class="bi bi-heart-fill"></i> 小红书数据获取工具
            </h1>
            
            <!-- 导航标签 -->
            <ul class="nav nav-tabs" id="mainTab" role="tablist">
                <li class="nav-item" role="presentation">
                    <button class="nav-link active" id="single-tab" data-bs-toggle="tab" data-bs-target="#single" type="button">
                        <i class="bi bi-link-45deg"></i> 单个获取
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link" id="batch-tab" data-bs-toggle="tab" data-bs-target="#batch" type="button">
                        <i class="bi bi-file-earmark-spreadsheet"></i> 批量处理
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link" id="help-tab" data-bs-toggle="tab" data-bs-target="#help" type="button">
                        <i class="bi bi-question-circle"></i> 使用说明
                    </button>
                </li>
            </ul>

            <div class="tab-content" id="mainTabContent">
                <!-- 单个获取标签页 -->
                <div class="tab-pane fade show active" id="single" role="tabpanel">
                    <div class="row mt-4">
                        <div class="col-md-8 mx-auto">
                            <div class="card">
                                <div class="card-header">
                                    <h5 class="mb-0"><i class="bi bi-link-45deg"></i> 获取单个笔记信息</h5>
                                </div>
                                <div class="card-body">
                                    <!-- Cookie设置 - 现在为必填项 -->
                                    <div class="mb-3">
                                        <label for="singleCookie" class="form-label">
                                            <span class="text-danger">*</span> Cookie值（必填）：
                                        </label>
                                        <textarea class="form-control" id="singleCookie" rows="3" 
                                                placeholder="请从浏览器开发者工具中复制Cookie值..." required></textarea>
                                        <div class="form-text">
                                            <i class="bi bi-info-circle text-primary"></i> 
                                            为确保数据获取成功，必须提供Cookie。从浏览器开发者工具 → Network → 请求头中复制完整的Cookie值
                                        </div>
                                    </div>
                                    
                                    <div class="mb-3">
                                        <label for="singleUrl" class="form-label">小红书链接：</label>
                                        <input type="url" class="form-control" id="singleUrl" 
                                               placeholder="粘贴小红书笔记链接...">
                                    </div>
                                    
                                    <button type="button" class="btn btn-primary w-100" id="getSingleBtn">
                                        <i class="bi bi-search"></i> 获取数据
                                    </button>
                                </div>
                            </div>
                            
                            <!-- 单个结果显示 -->
                            <div id="singleResult" style="display: none;"></div>
                        </div>
                    </div>
                </div>

                <!-- 批量处理标签页 -->
                <div class="tab-pane fade" id="batch" role="tabpanel">
                    <div class="row mt-4">
                        <div class="col-md-10 mx-auto">
                            <div class="card">
                                <div class="card-header">
                                    <h5 class="mb-0"><i class="bi bi-file-earmark-spreadsheet"></i> 批量处理Excel文件</h5>
                                </div>
                                <div class="card-body">
                                    <!-- Cookie设置 - 现在为必填项 -->
                                    <div class="mb-3">
                                        <label for="batchCookie" class="form-label">
                                            <span class="text-danger">*</span> Cookie值（必填）：
                                        </label>
                                        <textarea class="form-control" id="batchCookie" rows="3" 
                                                placeholder="请从浏览器开发者工具中复制Cookie值..." required></textarea>
                                        <div class="form-text">
                                            <i class="bi bi-info-circle text-primary"></i> 
                                            批量处理需要Cookie以确保数据获取成功，请从浏览器开发者工具 → Network → 请求头中复制完整的Cookie值
                                        </div>
                                    </div>
                                    
                                    <!-- 文件上传区域 -->
                                    <div class="drop-zone mb-3" id="dropZone">
                                        <i class="bi bi-cloud-upload display-4 text-primary mb-3"></i>
                                        <h5>拖拽Excel文件到此处</h5>
                                        <p class="text-muted">或点击选择文件上传</p>
                                        <input type="file" id="batchFile" accept=".xlsx,.xls" style="display: none;">
                                        <button type="button" class="btn btn-outline-primary" onclick="document.getElementById('batchFile').click()">
                                            <i class="bi bi-folder2-open"></i> 选择文件
                                        </button>
                                    </div>
                                    
                                    <div class="d-flex gap-2 mb-3">
                                        <button type="button" class="btn btn-outline-primary" id="downloadTemplate">
                                            <i class="bi bi-download"></i> 下载模板
                                        </button>
                                        <button type="button" class="btn btn-primary" id="processBatchBtn" disabled>
                                            <i class="bi bi-play-circle"></i> 开始处理
                                        </button>
                                    </div>
                                    
                                    <!-- 进度显示 -->
                                    <div id="progressContainer" style="display: none;">
                                        <div class="processing-info">
                                            <h6><i class="bi bi-gear-fill"></i> 处理进度</h6>
                                            <div class="progress mb-2">
                                                <div class="progress-bar" id="progressBar" role="progressbar" style="width: 0%"></div>
                                            </div>
                                            <div class="row text-center">
                                                <div class="col-3">
                                                    <small class="text-muted">进度</small>
                                                    <div id="progressText">0%</div>
                                                </div>
                                                <div class="col-3">
                                                    <small class="text-muted">总数</small>
                                                    <div id="totalCount">0</div>
                                                </div>
                                                <div class="col-3">
                                                    <small class="text-muted">成功</small>
                                                    <div id="successCount" class="text-success">0</div>
                                                </div>
                                                <div class="col-3">
                                                    <small class="text-muted">失败</small>
                                                    <div id="errorCount" class="text-danger">0</div>
                                                </div>
                                            </div>
                                            <div class="mt-2">
                                                <small class="text-muted">当前处理：</small>
                                                <div id="currentUrl" class="text-truncate" style="font-size: 0.9em;"></div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            
                            <!-- 批量结果显示 -->
                            <div id="batchResult" style="display: none;"></div>
                        </div>
                    </div>
                </div>

                <!-- 使用说明标签页 -->
                <div class="tab-pane fade" id="help" role="tabpanel">
                    <div class="row mt-4">
                        <div class="col-md-10 mx-auto">
                            <div class="card">
                                <div class="card-header">
                                    <h5 class="mb-0"><i class="bi bi-question-circle"></i> 使用说明</h5>
                                </div>
                                <div class="card-body">
                                    <h6><i class="bi bi-1-circle-fill text-primary"></i> 单个获取</h6>
                                    <ul>
                                        <li>先从浏览器开发者工具中复制Cookie值（必须）</li>
                                        <li>复制小红书笔记链接（支持分享链接和网页链接）</li>
                                        <li>粘贴到对应输入框中</li>
                                        <li>点击"获取数据"按钮</li>
                                    </ul>
                                    
                                    <h6 class="mt-4"><i class="bi bi-2-circle-fill text-primary"></i> 批量处理</h6>
                                    <ul>
                                        <li>先从浏览器开发者工具中复制Cookie值（必须）</li>
                                        <li>下载Excel模板文件</li>
                                        <li>在第一列填入小红书链接（每行一个）</li>
                                        <li>上传填好的Excel文件</li>
                                        <li>点击"开始处理"等待完成</li>
                                        <li>下载处理结果文件</li>
                                    </ul>
                                    
                                    <h6 class="mt-4"><i class="bi bi-3-circle-fill text-primary"></i> Cookie设置（必填）</h6>
                                    <ol>
                                        <li>在浏览器中打开小红书网站并登录</li>
                                        <li>按F12打开开发者工具</li>
                                        <li>切换到Network标签</li>
                                        <li>刷新页面，找到任意请求</li>
                                        <li>复制Request Headers中的Cookie值</li>
                                        <li>粘贴到工具中的Cookie输入框</li>
                                    </ol>
                                    
                                    <div class="alert alert-info mt-4">
                                        <h6><i class="bi bi-info-circle"></i> 注意事项</h6>
                                        <ul class="mb-0">
                                            <li><strong class="text-danger">Cookie是必需的</strong>，用于确保数据获取成功</li>
                                            <li>批量处理时请耐心等待，避免频繁刷新</li>
                                            <li>如遇到问题，可尝试更换Cookie或稍后重试</li>
                                            <li>工具仅用于数据分析，请遵守相关使用条款</li>
                                            <li><strong>不要分享你的Cookie给他人</strong>，以保护账户安全</li>
                                        </ul>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        let currentFileId = null;
        let progressInterval = null;

        // Cookie现在是必填项，不需要切换处理逻辑

        // 单个获取
        document.getElementById('getSingleBtn').addEventListener('click', async function() {
            const btn = this;
            const url = document.getElementById('singleUrl').value.trim();
            const cookie = document.getElementById('singleCookie').value.trim();

            if (!url) {
                showAlert('danger', '请输入小红书链接', 'singleResult');
                return;
            }

            if (!cookie) {
                showAlert('danger', '请提供Cookie值。Cookie是必需的，用于确保数据获取成功。', 'singleResult');
                return;
            }

            btn.disabled = true;
            btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>获取中...';

            try {
                const response = await fetch('/api/single', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ url, cookie })
                });

                const data = await response.json();

                if (data.success) {
                    showSingleResult(data.data);
                } else {
                    showAlert('danger', data.error || '获取失败', 'singleResult');
                }
            } catch (error) {
                showAlert('danger', '网络请求失败：' + error.message, 'singleResult');
            } finally {
                btn.disabled = false;
                btn.innerHTML = '<i class="bi bi-search"></i> 获取数据';
            }
        });

        // 文件拖拽处理
        const dropZone = document.getElementById('dropZone');
        const fileInput = document.getElementById('batchFile');

        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            dropZone.addEventListener(eventName, preventDefaults, false);
        });

        function preventDefaults(e) {
            e.preventDefault();
            e.stopPropagation();
        }

        ['dragenter', 'dragover'].forEach(eventName => {
            dropZone.addEventListener(eventName, highlight, false);
        });

        ['dragleave', 'drop'].forEach(eventName => {
            dropZone.addEventListener(eventName, unhighlight, false);
        });

        function highlight(e) {
            dropZone.classList.add('drag-over');
        }

        function unhighlight(e) {
            dropZone.classList.remove('drag-over');
        }

        dropZone.addEventListener('drop', handleDrop, false);
        dropZone.addEventListener('click', () => fileInput.click());

        function handleDrop(e) {
            const dt = e.dataTransfer;
            const files = dt.files;
            handleFiles(files);
        }

        fileInput.addEventListener('change', function() {
            handleFiles(this.files);
        });

        async function handleFiles(files) {
            if (files.length === 0) return;

            const file = files[0];
            if (!file.name.match(/\\.(xlsx|xls)$/i)) {
                showAlert('danger', '请选择Excel文件（.xlsx或.xls）', 'batchResult');
                return;
            }

            const formData = new FormData();
            formData.append('file', file);

            try {
                const response = await fetch('/api/batch/upload', {
                    method: 'POST',
                    body: formData
                });

                const data = await response.json();

                if (data.success) {
                    currentFileId = data.file_id;
                    document.getElementById('processBatchBtn').disabled = false;
                    showAlert('success', `文件上传成功！总行数：${data.total_rows}，有效链接：${data.valid_urls}个`, 'batchResult');
                } else {
                    showAlert('danger', data.error || '文件上传失败', 'batchResult');
                }
            } catch (error) {
                showAlert('danger', '文件上传失败：' + error.message, 'batchResult');
            }
        }

        // 批量处理
        document.getElementById('processBatchBtn').addEventListener('click', async function() {
            if (!currentFileId) {
                showAlert('danger', '请先上传文件', 'batchResult');
                return;
            }

            const btn = this;
            const cookie = document.getElementById('batchCookie').value.trim();

            if (!cookie) {
                showAlert('danger', '请提供Cookie值。批量处理需要Cookie以确保数据获取成功。', 'batchResult');
                btn.disabled = false;
                return;
            }

            btn.disabled = true;
            btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>处理中...';

            // 显示进度容器
            document.getElementById('progressContainer').style.display = 'block';

            try {
                // 启动批量处理
                fetch('/api/batch/process', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ file_id: currentFileId, cookie })
                }).then(response => response.json()).then(data => {
                    if (data.success) {
                        showBatchResult(data);
                    } else {
                        showAlert('danger', data.error || '处理失败', 'batchResult');
                    }
                    btn.disabled = false;
                    btn.innerHTML = '<i class="bi bi-play-circle"></i> 开始处理';
                    document.getElementById('progressContainer').style.display = 'none';
                    if (progressInterval) {
                        clearInterval(progressInterval);
                        progressInterval = null;
                    }
                }).catch(error => {
                    showAlert('danger', '处理失败：' + error.message, 'batchResult');
                    btn.disabled = false;
                    btn.innerHTML = '<i class="bi bi-play-circle"></i> 开始处理';
                    document.getElementById('progressContainer').style.display = 'none';
                    if (progressInterval) {
                        clearInterval(progressInterval);
                        progressInterval = null;
                    }
                });

                // 开始轮询进度
                progressInterval = setInterval(updateProgress, 1000);

            } catch (error) {
                showAlert('danger', '处理失败：' + error.message, 'batchResult');
                btn.disabled = false;
                btn.innerHTML = '<i class="bi bi-play-circle"></i> 开始处理';
                document.getElementById('progressContainer').style.display = 'none';
            }
        });

        // 更新进度
        async function updateProgress() {
            if (!currentFileId) return;

            try {
                const response = await fetch(`/api/batch/progress/${currentFileId}`);
                const data = await response.json();

                if (data.success) {
                    const progress = data.progress;
                    
                    // 更新进度条
                    document.getElementById('progressBar').style.width = progress.percentage + '%';
                    document.getElementById('progressText').textContent = `${progress.percentage}% (${progress.processed}/${progress.total})`;
                    document.getElementById('totalCount').textContent = progress.total;
                    document.getElementById('successCount').textContent = progress.success;
                    document.getElementById('errorCount').textContent = progress.error;
                    
                    // 更新当前处理的URL，显示简化版本
                    const currentUrlDiv = document.getElementById('currentUrl');
                    if (progress.current_url) {
                        // 提取并简化URL显示
                        let displayUrl = progress.current_url;
                        if (displayUrl.length > 80) {
                            const match = displayUrl.match(/explore\/([^?]+)/);
                            if (match) {
                                displayUrl = `.../${match[1]}...`;
                            } else {
                                displayUrl = displayUrl.substring(0, 80) + '...';
                            }
                        }
                        currentUrlDiv.textContent = `正在处理: ${displayUrl}`;
                        currentUrlDiv.className = 'text-info small';
                    } else if (progress.status === 'completed') {
                        currentUrlDiv.textContent = '✅ 所有任务处理完成';
                        currentUrlDiv.className = 'text-success';
                    } else if (progress.status === 'processing') {
                        currentUrlDiv.textContent = '⏳ 准备处理下一个...';
                        currentUrlDiv.className = 'text-muted small';
                    }

                    // 估算剩余时间
                    if (progress.status === 'processing' && progress.processed > 0) {
                        const remaining = progress.total - progress.processed;
                        if (remaining > 0) {
                            const avgTimePerItem = 3; // 估算每个项目3秒
                            const etaSeconds = remaining * avgTimePerItem;
                            const etaMinutes = Math.floor(etaSeconds / 60);
                            const etaSecondsRem = etaSeconds % 60;
                            
                            let etaText = '';
                            if (etaMinutes > 0) {
                                etaText = `预计还需 ${etaMinutes}分${etaSecondsRem}秒`;
                            } else {
                                etaText = `预计还需 ${etaSecondsRem}秒`;
                            }
                            
                            const etaDiv = document.getElementById('eta') || (() => {
                                const div = document.createElement('div');
                                div.id = 'eta';
                                div.className = 'text-muted small mt-1';
                                document.getElementById('progressContainer').appendChild(div);
                                return div;
                            })();
                            etaDiv.textContent = etaText;
                        }
                    }

                    // 如果完成，停止轮询并清理
                    if (progress.status === 'completed') {
                        if (progressInterval) {
                            clearInterval(progressInterval);
                            progressInterval = null;
                        }
                        
                        // 移除ETA显示
                        const etaDiv = document.getElementById('eta');
                        if (etaDiv) {
                            etaDiv.remove();
                        }
                        
                        // 显示完成通知
                        setTimeout(() => {
                            if (progress.success > 0) {
                                showAlert('success', `🎉 处理完成！成功获取 ${progress.success} 个笔记，失败 ${progress.error} 个`, 'batchResult');
                            } else {
                                showAlert('warning', `⚠️ 处理完成，但所有笔记都获取失败。请检查链接是否正确或稍后重试。`, 'batchResult');
                            }
                        }, 500);
                    }
                }
            } catch (error) {
                console.error('获取进度失败:', error);
                // 如果多次获取进度失败，停止轮询
                if (progressInterval) {
                    clearInterval(progressInterval);
                    progressInterval = null;
                    showAlert('danger', '获取进度失败，请刷新页面重试', 'batchResult');
                }
            }
        }

        // 下载模板
        document.getElementById('downloadTemplate').addEventListener('click', function() {
            window.open('/api/template', '_blank');
        });

        // 显示提示信息
        function showAlert(type, message, containerId) {
            const container = document.getElementById(containerId);
            container.innerHTML = `
                <div class="alert alert-${type} mt-3" role="alert">
                    <i class="bi bi-${type === 'success' ? 'check-circle' : type === 'danger' ? 'x-circle' : 'info-circle'}"></i>
                    ${message}
                </div>
            `;
            container.style.display = 'block';
        }

        // 显示单个结果
        function showSingleResult(data) {
            const html = `
                <div class="card mt-3">
                    <div class="card-header">
                        <h6 class="mb-0"><i class="bi bi-check-circle text-success"></i> 获取结果</h6>
                    </div>
                    <div class="card-body">
                        <div class="table-responsive">
                            <table class="table result-table">
                                <tbody>
                                    <tr><th width="120">笔记标题</th><td>${data.笔记标题 || '未获取'}</td></tr>
                                    <tr><th>用户名</th><td>${data.用户名 || '未获取'}</td></tr>
                                    <tr><th>形式</th><td><span class="badge ${data.形式 === '视频' ? 'bg-danger' : data.形式 === '图文' ? 'bg-primary' : 'bg-secondary'}">${data.形式 || '未获取'}</span></td></tr>
                                    <tr><th>笔记正文</th><td>${data.笔记正文 || '未获取'}</td></tr>
                                    <tr><th>笔记标签</th><td>${data.笔记标签 || '未获取'}</td></tr>
                                    <tr><th>发布时间</th><td>${data.发布时间 || '未获取'}</td></tr>
                                    <tr><th>点赞数</th><td>${data.点赞数 || '未获取'}</td></tr>
                                    <tr><th>收藏数</th><td>${data.收藏数 || '未获取'}</td></tr>
                                    <tr><th>评论数</th><td>${data.评论数 || '未获取'}</td></tr>
                                    <tr><th>分享数</th><td>${data.分享数 || '未获取'}</td></tr>
                                    ${data.错误信息 ? `<tr><th>错误信息</th><td class="text-danger">${data.错误信息}</td></tr>` : ''}
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            `;
            
            const container = document.getElementById('singleResult');
            container.innerHTML = html;
            container.style.display = 'block';
        }

        // 显示批量结果
        function showBatchResult(data) {
            const stats = data.statistics;
            const html = `
                <div class="card mt-3">
                    <div class="card-header">
                        <h6 class="mb-0"><i class="bi bi-check-circle text-success"></i> 处理完成</h6>
                    </div>
                    <div class="card-body">
                        <div class="row text-center mb-3">
                            <div class="col-3">
                                <h5 class="text-primary">${stats.total_processed}</h5>
                                <small class="text-muted">总处理数</small>
                            </div>
                            <div class="col-3">
                                <h5 class="text-success">${stats.success_count}</h5>
                                <small class="text-muted">成功数</small>
                            </div>
                            <div class="col-3">
                                <h5 class="text-danger">${stats.error_count}</h5>
                                <small class="text-muted">失败数</small>
                            </div>
                            <div class="col-3">
                                <h5 class="text-info">${stats.success_rate}</h5>
                                <small class="text-muted">成功率</small>
                            </div>
                        </div>
                        <div class="text-center">
                            <a href="/api/download/${data.result_file}" class="btn btn-success">
                                <i class="bi bi-download"></i> 下载结果文件
                            </a>
                        </div>
                    </div>
                </div>
            `;
            
            const container = document.getElementById('batchResult');
            container.innerHTML = html;
            container.style.display = 'block';
        }
    </script>
</body>
</html>
"""

if __name__ == '__main__':
    print("🚀 启动小红书数据获取 Web 服务")
    print("📋 服务地址: http://localhost:5000")
    print("📝 API文档:")
    print("   GET  /api/health             - 健康检查")
    print("   POST /api/single             - 获取单个笔记")
    print("   POST /api/batch/upload       - 上传批量文件")
    print("   POST /api/batch/process      - 处理批量文件")
    print("   GET  /api/batch/progress/<id> - 获取处理进度")
    print("   GET  /api/download/<file>    - 下载结果文件")
    print("   GET  /api/template           - 下载模板文件")
    print("="*60)
    
    app.run(
        debug=True,
        host='0.0.0.0',
        port=5000
    )